
/**
 * 
 * Ashish Tomar
 * IDS Project - 2
 * Port Pairing and Statistics Merger
 * 
 */

#include <pcap.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h> 
#include <map>
#include <utility>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
#include <math.h>
using namespace std;


double current_time;
double start_time;
double diff_time;
int pkt_count;
long double buffer_total;
double total_time1;
double total_time2;
double final_time;
int totaltimefile1;
int totaltimefile2;

ofstream out;

/* tcpdump header (ether.h) defines ETHER_HDRLEN) */
#ifndef ETHER_HDRLEN 
#define ETHER_HDRLEN 14
#define SIZE_ETHERNET 14
#endif

typedef u_int tcp_seq;



struct sniff_tcp {
	u_short th_sport;	/* source port */
	u_short th_dport;	/* destination port */
	tcp_seq th_seq;		/* sequence number */
	tcp_seq th_ack;		/* acknowledgement number */

	u_char th_offx2;	/* data offset, rsvd */
#define TH_OFF(th)	(((th)->th_offx2 & 0xf0) >> 4)
	u_char th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
	u_short th_win;		/* window */
	u_short th_sum;		/* checksum */
	u_short th_urp;		/* urgent pointer */
};



u_int16_t handle_ethernet
(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
		packet);
u_char* handle_IP
(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
		packet);



struct my_ip {
	u_int8_t	ip_vhl;		/* header length, version */
#define IP_V(ip)	(((ip)->ip_vhl & 0xf0) >> 4)
#define IP_HL(ip)	((ip)->ip_vhl & 0x0f)
	u_int8_t	ip_tos;		/* type of service */
	u_int16_t	ip_len;		/* total length */
	u_int16_t	ip_id;		/* identification */
	u_int16_t	ip_off;		/* fragment offset field */
#define	IP_DF 0x4000			/* dont fragment flag */
#define	IP_MF 0x2000			/* more fragments flag */
#define	IP_OFFMASK 0x1fff		/* mask for fragmenting bits */
	u_int8_t	ip_ttl;		/* time to live */
	u_int8_t	ip_p;		/* protocol */
	u_int16_t	ip_sum;		/* checksum */
	struct	in_addr ip_src,ip_dst;	/* source and dest address */
};



class portpair{
public: 
	long int src_port;
	long int dst_port;

	bool operator()(const class portpair s1,const  class portpair s2) const{
		if(s1.src_port != s2.src_port)
		{
			if(s1.src_port < s2.src_port)
			{
				return true;
			}
			else
				return false;
		}
		else{
			if(s1.dst_port < s2.dst_port)
			{
				return true;
			}
			else
				return false;
		}

	}
};



class stats{
public:
	long double volume;//(total pkts size/diff_time)
	double packet_rate;
	double avg_packet_size;//(total pkts size/count)
	//double cumulative_packet_size;
	int count;
	double time;
	double pkt_rate_mean;
	double stdevpacketrate;
	double stdevpacketsize;
	double stdevpacketvol;
	double pkt_vol_mean;


};



map <class portpair, class stats, class portpair> port_pairs;
map <class portpair, class stats, class portpair> secondport_pairs;
map <class portpair, class stats, class portpair> ::iterator itr;
map <class portpair, class stats, class portpair> ::iterator p;


void addtomapfirst(class portpair tempp, class stats st_temp){
	// port_pairs.insert ( pair<class portpair, int >(tempp,100) );

	itr = port_pairs.find(tempp);

	total_time1=st_temp.time;

	if (itr == port_pairs.end()){

		port_pairs.insert ( pair<class portpair, class stats >(tempp,st_temp) );

		//cout<<"yes"<<port_pairs[tempp];

	}
	else{


	}
}






void mergemaps(){

	for(p = secondport_pairs.begin(); p != secondport_pairs.end(); p++) {
		itr = port_pairs.find(p->first);	

		if (itr == port_pairs.end()){

			class stats stat_temp;

			stat_temp.count = p->second.count;
			stat_temp.time = final_time;
			stat_temp.packet_rate=(double)(	stat_temp.count/stat_temp.time);

			stat_temp.avg_packet_size=(double)((p->second.count*p->second.avg_packet_size )/stat_temp.count);
			stat_temp.volume=(long double)((p->second.count*p->second.avg_packet_size )/final_time);
			stat_temp.stdevpacketsize = p->second.stdevpacketsize;


			stat_temp.pkt_rate_mean = ((p->second.pkt_rate_mean*totaltimefile2)+(0*totaltimefile1))/(totaltimefile1+totaltimefile2);

			stat_temp.stdevpacketrate = sqrt(
					((((0 * 0)*(totaltimefile1-1))+((p->second.stdevpacketrate * p->second.stdevpacketrate)*(totaltimefile2-1)))/(totaltimefile1+totaltimefile2))
			);


			stat_temp.pkt_vol_mean = ((p->second.pkt_vol_mean*totaltimefile2)+(0*totaltimefile1))/(totaltimefile1+totaltimefile2);

			stat_temp.stdevpacketvol = sqrt(
					((((0 * 0)*(totaltimefile1-1))+((p->second.stdevpacketvol * p->second.stdevpacketvol)*(totaltimefile2-1)))/(totaltimefile1+totaltimefile2))
			);

			port_pairs.insert ( pair<class portpair, class stats >(p->first,stat_temp) );

			//cout<<"yes"<<port_pairs[tempp];

		}
		else{

			itr->second.packet_rate=(double)((itr->second.packet_rate * itr->second.time + p->second.packet_rate * p->second.time  )/final_time);

			itr->second.volume = (long double)(((  itr->second.avg_packet_size * itr->second.count + p->second.avg_packet_size * p->second.count ))/final_time);


			itr->second.avg_packet_size = (double)(( itr->second.avg_packet_size * itr->second.count + p->second.avg_packet_size * p->second.count)/(itr->second.count + p->second.count));

			itr->second.stdevpacketsize = sqrt(
					((((itr->second.stdevpacketsize * itr->second.stdevpacketsize)*(itr->second.count-1))+((p->second.stdevpacketsize * p->second.stdevpacketsize)*(p->second.count-1)))/(p->second.count+itr->second.count))
			);


			itr->second.pkt_rate_mean = ((itr->second.pkt_rate_mean*totaltimefile1)+(p->second.pkt_rate_mean*totaltimefile2))/(totaltimefile1+totaltimefile2);

			itr->second.stdevpacketrate = sqrt(
					((((itr->second.stdevpacketrate * itr->second.stdevpacketrate)*(totaltimefile1-1))+((p->second.stdevpacketrate * p->second.stdevpacketrate)*(totaltimefile2-1)))/(totaltimefile1+totaltimefile2))
			);


			itr->second.pkt_vol_mean = ((itr->second.pkt_vol_mean*totaltimefile1)+(p->second.pkt_vol_mean*totaltimefile2))/(totaltimefile1+totaltimefile2);

			itr->second.stdevpacketvol = sqrt(
					((((itr->second.stdevpacketvol * itr->second.stdevpacketvol)*(totaltimefile1-1))+((p->second.stdevpacketvol * p->second.stdevpacketvol)*(totaltimefile2-1)))/(totaltimefile1+totaltimefile2))
			);


			itr->second.time = final_time;
			itr->second.count = itr->second.count + p->second.count;
			//pooled sp


		}

	}

	//unupdated records from first map
	for(p = port_pairs.begin(); p != port_pairs.end(); p++) {

		if(p->second.time!=final_time){
			//cout << "yes"  ;
			p->second.time=final_time;
			p->second.packet_rate=(double)(	p->second.count/p->second.time);

			p->second.avg_packet_size=(double)((p->second.count * p->second.avg_packet_size )/p->second.count);
			p->second.volume=(long double)((p->second.count*p->second.avg_packet_size )/final_time);
			p->second.pkt_rate_mean = ((p->second.pkt_rate_mean*totaltimefile1)+(0*totaltimefile2))/(totaltimefile1+totaltimefile2);

			p->second.stdevpacketrate = sqrt(
					((((0 * 0)*(totaltimefile2-1))+((p->second.stdevpacketrate * p->second.stdevpacketrate)*(totaltimefile1-1)))/(totaltimefile1+totaltimefile2))
			);


			p->second.pkt_vol_mean = ((p->second.pkt_vol_mean*totaltimefile1)+(0*totaltimefile2))/(totaltimefile1+totaltimefile2);

			p->second.stdevpacketvol = sqrt(
					((((0 * 0)*(totaltimefile2-1))+((p->second.stdevpacketvol * p->second.stdevpacketvol)*(totaltimefile1-1)))/(totaltimefile1+totaltimefile2))
			);





		}

	}

}




void addtomapsecond(class portpair tempp, class stats st_temp){
	// port_pairs.insert ( pair<class portpair, int >(tempp,100) );
	itr = secondport_pairs.find(tempp);

	total_time2=st_temp.time;
	final_time =total_time2+total_time1;
	if (itr == secondport_pairs.end()){

		secondport_pairs.insert ( pair<class portpair, class stats >(tempp,st_temp) );

	}
	else{

	}
}




void iterateOverMap(){

	for(p = port_pairs.begin(); p != port_pairs.end(); p++) {
		out << p->first.src_port ;
		out << "\t" << p->first.dst_port ;
		out << "\t" << p->second.packet_rate ;
		out << "\t" << p->second.avg_packet_size;
		out << "\t" << p->second.volume;
		out << "\t" << p->second.count ;
		out << "\t" <<  p->second.time ;
		out << "\t" << p->second.stdevpacketsize ;
		out << "\t" << p->second.pkt_rate_mean ;
		out << "\t" << p->second.stdevpacketrate ;
		out << "\t" << p->second.pkt_vol_mean ;
		out << "\t" << p->second.stdevpacketvol<< endl ;

	}
	out<<endl;
}


void calculatetotalstats(){


	double pk_total_count=0;
	long double total_buffer_pkts=0;


	for(p = port_pairs.begin(); p != port_pairs.end(); p++) {

		total_buffer_pkts+=(p->second.avg_packet_size * p->second.count);
		pk_total_count += p->second.count ;

	}

	cout << endl;
	cout << "Total packets "<< pk_total_count << endl;
	cout << "Total time "<< (final_time/3600) <<" hrs" << endl;
	cout << "Total pkt rate "<< (double)(pk_total_count/final_time) <<endl;
	cout << "Total Avg Bytes "<< (double)(total_buffer_pkts/pk_total_count) << endl;
	cout << "Total Volume "<< (long double)(total_buffer_pkts/final_time) <<  endl;

}


void readfileone(char * filename){

	string s;
	std::string line;
	ifstream inFile;
	inFile.open(filename);

	while (std::getline(inFile, line)){
		// cout << line;
		stringstream ss ;
		ss << line;
		vector<string> v;
		while (getline( ss, line, '\t' )) v.push_back( line );
		class portpair tempp;
		class stats stat_temp;
		// cout << "The tokens are:\n";
		for (int i = 0; i < v.size(); i++){
			// cout << i << ": " << v[ i ] << endl;
			if(i==0){

				tempp.src_port=atoi(v[i].c_str());
				// cout<<tempp.src_port;
			}
			if(i==1){

				tempp.dst_port=atoi(v[i].c_str());
				//   cout<<tempp.dst_port;
			}
			if(i==2){
				std::stringstream sss(v[i]);
				sss >> stat_temp.packet_rate;
				//stat_temp.packet_rate=atod(v[i].c_str());
				//  cout<<stat_temp.packet_rate;
			}
			if(i==3){
				std::stringstream sss(v[i]);
				sss >> stat_temp.avg_packet_size;

				//	cout<<endl<<stat_temp.avg_packet_size;
			}
			if(i==4){
				std::stringstream sss(v[i]);
				sss >> stat_temp.volume;

				//  	cout<<endl<<stat_temp.volume;

			}
			if(i==5){
				stat_temp.count=atoi(v[i].c_str());
				//cout <<endl <<stat_temp.count<<endl;

			}
			if(i==6){
				std::stringstream sss(v[i]);
				sss >> stat_temp.time;
				totaltimefile1=(int)((stat_temp.time/3600)+1);


			}

			if(i==7){
				std::stringstream sss(v[i]);
				sss >> stat_temp.stdevpacketsize;

			}
			if(i==8){
				std::stringstream sss(v[i]);
				sss >> stat_temp.pkt_rate_mean;

			}

			if(i==9){
				std::stringstream sss(v[i]);
				sss >> stat_temp.stdevpacketrate;

			}

			if(i==10){
				std::stringstream sss(v[i]);
				sss >> stat_temp.pkt_vol_mean;
			}


			if(i==11){
				std::stringstream sss(v[i]);
				sss >> stat_temp.stdevpacketvol;

			}

		}


		addtomapfirst(tempp, stat_temp);
	}

}


void readfiletwo(char * filename){

	string s;
	std::string line;
	ifstream inFile;
	inFile.open(filename);

	while (std::getline(inFile, line)){
		// cout << line;
		stringstream ss ;
		ss << line;
		vector<string> v;
		while (getline( ss, line, '\t' )) v.push_back( line );
		class portpair tempp;
		class stats stat_temp;
		// cout << "The tokens are:\n";
		for (int i = 0; i < v.size(); i++){
			// cout << i << ": " << v[ i ] << endl;
			if(i==0){

				tempp.src_port=atoi(v[i].c_str());
				// cout<<tempp.src_port;
			}
			if(i==1){

				tempp.dst_port=atoi(v[i].c_str());
				//   cout<<tempp.dst_port;
			}
			if(i==2){
				std::stringstream sss(v[i]);
				sss >> stat_temp.packet_rate;
				//stat_temp.packet_rate=atod(v[i].c_str());
				//  cout<<stat_temp.packet_rate;
			}
			if(i==3){
				std::stringstream sss(v[i]);
				sss >> stat_temp.avg_packet_size;

				//	cout<<endl<<stat_temp.avg_packet_size;
			}
			if(i==4){
				std::stringstream sss(v[i]);
				sss >> stat_temp.volume;

				//  	cout<<endl<<stat_temp.volume;

			}
			if(i==5){
				stat_temp.count=atoi(v[i].c_str());
				//cout <<endl <<stat_temp.count<<endl;

			}
			if(i==6){
				std::stringstream sss(v[i]);
				sss >> stat_temp.time;
				totaltimefile2=(int)((stat_temp.time/3600)+1);

			}
			if(i==7){
				std::stringstream sss(v[i]);
				sss >> stat_temp.stdevpacketsize;

			}


			if(i==8){
				std::stringstream sss(v[i]);
				sss >> stat_temp.pkt_rate_mean;



			}

			if(i==9){
				std::stringstream sss(v[i]);
				sss >> stat_temp.stdevpacketrate;

			}



			if(i==10){
				std::stringstream sss(v[i]);
				sss >> stat_temp.pkt_vol_mean;
			}


			if(i==11){
				std::stringstream sss(v[i]);
				sss >> stat_temp.stdevpacketvol;
			}


		}


		addtomapsecond(tempp, stat_temp);
	}
}




int main(int argc,char **argv){ 

	if(argc != 4){
		fprintf(stdout,"Usage: %s \"filter program\"\n"	,argv[0]);
		return 0;
	}

	out.open(argv[3]);
	readfileone(argv[1]); // create map 1
	readfiletwo(argv[2]); // create map 2 
	//iterateOverMap();
	//iterateOverMap2();
	mergemaps();
	iterateOverMap();
	//calculatetotalstats();

	return 0;

}










